﻿using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Collections.Generic;
using System.Xml;

using WebRole1.DataService;

namespace WebRole1
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ajaxway
    {
        // Add [WebGet] attribute to use HTTP GET
        [OperationContract]
        public TreeCategoryNode[] GetChildCategory(string id, string cityId)
        {
            List<TreeCategoryNode> nodeList = new List<TreeCategoryNode>();
            try
            {
                int parentId = Convert.ToInt32(id);
                using (LocationsDBEntities locEntities = new LocationsDBEntities())
                {
                    System.Linq.IOrderedQueryable<Category> categories = null;

                    if (String.IsNullOrEmpty(cityId))
                    {
                        categories = from p in locEntities.Category
                                     where p.ParentID == parentId
                                     orderby p.CategoryName
                                     select p;
                    }
                    else
                    {
                        categories = from p in locEntities.Category
                                     where p.ParentID == parentId && p.City == null
                                     orderby p.CategoryName
                                     select p;
                    }

                    foreach (Category cat in categories)
                    {
                        nodeList.Add(new TreeCategoryNode(cat.CategoryID, cat.CategoryName, cat.CategorySvcUrl, cat.CategorySvcUrlType, false));
                    }

                    if (!String.IsNullOrEmpty(cityId))
                    {  //there is must a better linq query method to do this:
                        int cityIdInt = Convert.ToInt32(cityId);
                        var city = locEntities.City.First(f => f.CityID == cityIdInt);
                        city.Category.Load();
                        foreach (Category cat in city.Category)
                        {
                            if (cat.ParentID == parentId)
                            {
                                nodeList.Add(new TreeCategoryNode(cat.CategoryID, cat.CategoryName, cat.CategorySvcUrl, cat.CategorySvcUrlType, false));
                            }
                        }
                    }

                    foreach (TreeCategoryNode node in nodeList)
                    {
                        CheckCatNodeChildren(node, locEntities);
                    }

                }
            }
            catch
            {  //we might get an invaild id if the client passed wrong id
            }

            return nodeList.ToArray();
        }

        [OperationContract]
        public TreeCategoryNode[] GetChildCategoryNoCity(string id, string cityId)
        {
            List<TreeCategoryNode> nodeList = new List<TreeCategoryNode>();
            try
            {
                int parentId = Convert.ToInt32(id);
                using (LocationsDBEntities locEntities = new LocationsDBEntities())
                {
                    System.Linq.IOrderedQueryable<Category> categories = null;

                    categories = from p in locEntities.Category
                                 where p.ParentID == parentId && p.City == null
                                 orderby p.CategoryName
                                 select p;

                    foreach (Category cat in categories)
                    {
                        nodeList.Add(new TreeCategoryNode(cat.CategoryID, cat.CategoryName, cat.CategorySvcUrl, cat.CategorySvcUrlType, false));
                    }

                    foreach (TreeCategoryNode node in nodeList)
                    {
                        CheckCatNodeChildrenNoCity(node, locEntities);
                    }

                }
            }
            catch
            {  //we might get an invaild id if the client passed wrong id
            }

            return nodeList.ToArray();
        }

        private void CheckCatNodeChildrenNoCity(TreeCategoryNode cat, LocationsDBEntities locEntities)
        {
            var childCount = (from c in locEntities.Category where c.ParentID == cat.id && c.City == null select c).Count();
            bool hasChild = childCount > 0;

            cat.hasChildren = hasChild;
        }

        private void CheckCatNodeChildren(TreeCategoryNode cat, LocationsDBEntities locEntities)
        {
            var childCount = (from c in locEntities.Category where c.ParentID == cat.id select c).Count();
            bool hasChild = childCount > 0;

            cat.hasChildren = hasChild;
        }

        [OperationContract]
        public TreeCityNode[] GetCity(string id, string type)
        {
            List<TreeCityNode> nodeList = new List<TreeCityNode>();
            using (LocationsDBEntities locEntities = new LocationsDBEntities())
            {
                if (String.IsNullOrEmpty(type))
                {
                    int depth = 0;
                    if (String.IsNullOrEmpty(id) || Convert.ToInt32(id) == 0)
                    {
                        depth = 0;
                    }
                    else
                    {
                        depth = 1;
                    }

                    var countries = from p in locEntities.Country where p.Depth == depth orderby p.CountryName select p;
                    foreach (Country c in countries)
                    {
                        TreeCityNode myNode = new TreeCityNode(c.CountryID, c.CountryName, "country", "", true, 0, 0);
                        nodeList.Add(myNode);
                    }

                    if (depth == 0)
                    {
                        TreeCityNode myNode = new TreeCityNode(1, "More", "top", "", true, 0, 0);
                        nodeList.Add(myNode);
                    }
                }
                else if (type == "country")
                {
                    int countryID = Convert.ToInt32(id);
                    var country = locEntities.Country.First(f => f.CountryID == countryID);
                    //var states = from p in locEntities.State where p.Country == country orderby p.StateName select p;
                    //var states = from p in locEntities.State where p.Country == country orderby p.StateName select p;
                    country.State.Load();

                    foreach (State c in country.State.OrderBy(f => f.StateName))
                    {
                        TreeCityNode myNode = new TreeCityNode(c.StateID, c.StateName, "state", "", true, 0, 0);
                        nodeList.Add(myNode);
                    }
                }
                else if (type == "state")
                {
                    int stateID = Convert.ToInt32(id);
                    var state = locEntities.State.First(f => f.StateID == stateID);
                    //var cities = from p in locEntities.City where p.State == state orderby p.CityName select p;

                    state.City.Load();
                    foreach (City c in state.City.OrderBy(f => f.CityName))
                    {
                        TreeCityNode myNode = new TreeCityNode(c.CityID, c.CityName, "city", c.SearchName, false, c.Lat, c.Lon);
                        nodeList.Add(myNode);
                    }
                }

            }
            return nodeList.ToArray();
        }

        [OperationContract]
        public TreeCityNode[] GetCityByKeyword(string keyword, int take, int skip)
        {
            List<TreeCityNode> nodeList = new List<TreeCityNode>();
            using (LocationsDBEntities locEntities = new LocationsDBEntities())
            {
                var cities = (from p in locEntities.City where p.SearchName.StartsWith(keyword) orderby p.SearchName select p).Skip(skip).Take(take);
                foreach (City c in cities)
                {
                    TreeCityNode myNode = new TreeCityNode(c.CityID, c.CityName, "city", c.SearchName, false, c.Lat, c.Lon);
                    nodeList.Add(myNode);
                }
            }
            return nodeList.ToArray();
        }

        [OperationContract]
        public BasicLocation[] GetLocationsFromCSV(string url)
        {
            List<BasicLocation> nodeList = new List<BasicLocation>();
            try
            {
                System.Net.WebClient client = new System.Net.WebClient();
                string csvContent = csvContent = client.DownloadString(url);

                bool firstLine = true;
                int colname = 0;
                int colLatitude = 0;
                int colLongitude = 0;
                int colUrl = 0;

                int colCnt = 0;
                bool csvUseDoubleQuote = false;
                string[] sep = new string[] { "," };
                string tmp;

                //read 1st line
                char[] delimiters = new char[] { '\r', '\n' };
                foreach (string line in csvContent.Split(delimiters, StringSplitOptions.RemoveEmptyEntries))
                {
                    colCnt = 0;
                    if (firstLine)
                    {
                        firstLine = false;

                        if (line.StartsWith("\"") && line.Contains("\",\""))
                        {
                            csvUseDoubleQuote = true;
                            sep = new string[] { "\",\"" };
                        }

                        if (csvUseDoubleQuote)
                        {
                            tmp = line.Trim(new char[] { '"' });
                        }
                        else
                        {
                            tmp = line;
                        }

                        foreach (string colStrOri in tmp.Split(sep, StringSplitOptions.None))
                        {
                            string colStr = colStrOri.ToLower();
                            if (colStr.Contains("name"))
                            {
                                colname = colCnt;
                            }
                            else if (colStr.Contains("latitude"))
                            {
                                colLatitude = colCnt;
                            }
                            else if (colStr.Contains("longitude"))
                            {
                                colLongitude = colCnt;
                            }
                            else if (colStr.Contains("url") || colStr.Contains("http"))
                            {
                                colUrl = colCnt;
                            }

                            colCnt++;
                        }
                    }
                    else
                    {
                        if (csvUseDoubleQuote)
                        {
                            tmp = line.Trim(new char[] { '"' });
                        }
                        else
                        {
                            tmp = line;
                        }

                        string name = "", latitude = "", longtitude = "", csvUrl = "", desc = "";
                        foreach (string colStrOri in tmp.Split(sep, StringSplitOptions.None))
                        {
                            if (colCnt == colname)
                            {
                                name = colStrOri;
                            }
                            else if (colCnt == colLatitude)
                            {
                                latitude = colStrOri;
                            }
                            else if (colCnt == colLongitude)
                            {
                                longtitude = colStrOri;
                            }
                            else if (colCnt == colUrl)
                            {
                                csvUrl = colStrOri;
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(desc))
                                {
                                    desc += "<br/>";
                                }
                                desc += colStrOri;
                            }
                            colCnt++;
                        }
                        BasicLocation myNode = new BasicLocation(name, desc, csvUrl, Convert.ToDecimal(longtitude), Convert.ToDecimal(latitude));
                        nodeList.Add(myNode);

                    }
                }
            }
            catch // (Exception ex)
            {

            }

            return nodeList.ToArray();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="mlon"></param>
        /// <param name="mlat"></param>
        /// <param name="mark">The mark used for the client when callback function in the client is returned</param>
        /// <returns></returns>
        [OperationContract]
        public LocationDetail[] GetLocationDetail(string name, decimal mlon, decimal mlat)
        {
            List<LocationDetail> nodeList = new List<LocationDetail>();
            using (LocationsDBEntities locEntities = new LocationsDBEntities())
            {
                double lon = Convert.ToDouble(mlon);
                double lat = Convert.ToDouble(mlat);
                var locations = from p in locEntities.Location where p.Name == name select p;
                foreach (Location loc in locations)
                {
                    //select the matching longitude and latitude location with the same name
                    //matching means lon within 0.02, lat within 0.02

                    if (Convert.ToDouble(loc.Lat) <= (lat + 0.02) &&
                        Convert.ToDouble(loc.Lat) >= (lat - 0.02) &&
                        Convert.ToDouble(loc.Lon) <= (lon + 0.02) &&
                        Convert.ToDouble(loc.Lon) >= (lon - 0.02)
                       )
                    {
                        //won't work in sql azure CTP as it's not support MultipleActiveResultSets=true
                        //loc.Comment.Load();
                        //loc.Comment.Count()

                        LocationDetail myNode = new LocationDetail(loc.LocationID, loc.Url, loc.UrlLink1Mark, loc.UrlLink1, loc.UrlLink2Mark, loc.UrlLink2, loc.ImageUrl, loc.Rating, 0);
                        nodeList.Add(myNode);
                        break;
                    }
                }

                foreach (LocationDetail node in nodeList)
                {
                    node.commentCount = (from c in locEntities.vCommentUser where c.LocationID == node.id select c).Count();
                }

            }
            return nodeList.ToArray();
        }

    } // end of class ajaxway


    public class TreeCityNode
    {
        int m_id;
        string m_name;
        string m_type; //city, state, country
        string m_searchname;
        bool m_hasChildren;

        decimal m_longitude;
        decimal m_latitude;

        [DataMember]
        public int id
        {
            get { return m_id; }
            set { m_id = value; }
        }

        [DataMember]
        public string name
        {
            get { return m_name; }
            set { m_name = value; }
        }

        [DataMember]
        public bool hasChildren
        {
            get { return m_hasChildren; }
            set { m_hasChildren = value; }
        }

        [DataMember]
        public string type
        {
            get { return m_type; }
            set { m_type = value; }
        }

        [DataMember]
        public string searchname
        {
            get { return m_searchname; }
            set { m_searchname = value; }
        }

        [DataMember]
        public decimal longitude
        {
            get { return m_longitude; }
            set { m_longitude = value; }
        }

        [DataMember]
        public decimal latitude
        {
            get { return m_latitude; }
            set { m_latitude = value; }
        }

        public TreeCityNode(int cid, string cName, string cType, string cSearchName, bool chasChild, decimal cLat, decimal cLong)
        {
            m_id = cid;
            m_name = cName;
            m_type = cType;
            m_searchname = cSearchName;
            m_hasChildren = chasChild;
            m_latitude = cLat;
            m_longitude = cLong;
        }
        public TreeCityNode()
        {
        }
    }

    public class TreeCategoryNode
    {
        int m_id;

        string m_text;
        string m_url;
        string m_urlType;
        bool m_hasChildren;

        [DataMember]
        public int id
        {
            get { return m_id; }
            set { m_id = value; }
        }

        [DataMember]
        public string text
        {
            get { return m_text; }
            set { m_text = value; }
        }

        [DataMember]
        public bool hasChildren
        {
            get { return m_hasChildren; }
            set { m_hasChildren = value; }
        }

        [DataMember]
        public string url
        {
            get { return m_url; }
            set { m_url = value; }
        }

        [DataMember]
        public string urlType
        {
            get { return m_urlType; }
            set { m_urlType = value; }
        }

        public TreeCategoryNode(int cid, string ctext, string url, string urlType, bool chasChild)
        {
            m_id = cid;
            m_text = ctext;
            m_url = url;
            m_urlType = urlType;
            m_hasChildren = chasChild;
        }
        public TreeCategoryNode()
        {
        }
    }

    public class BasicLocation
    {
        string m_name;
        string m_desc; //city, state, country
        string m_url;
        decimal m_longitude;
        decimal m_latitude;

        [DataMember]
        public string name
        {
            get { return m_name; }
            set { m_name = value; }
        }

        [DataMember]
        public string desc
        {
            get { return m_desc; }
            set { m_desc = value; }
        }

        [DataMember]
        public string url
        {
            get { return m_url; }
            set { m_url = value; }
        }

        [DataMember]
        public decimal longitude
        {
            get { return m_longitude; }
            set { m_longitude = value; }
        }

        [DataMember]
        public decimal latitude
        {
            get { return m_latitude; }
            set { m_latitude = value; }
        }

        public BasicLocation(string cName, string cDesc, string cUrl, decimal cLongitude, decimal cLatitude)
        {
            m_name = cName;
            m_desc = cDesc;
            m_url = cUrl;
            m_longitude = cLongitude;
            m_latitude = cLatitude;
        }

        public BasicLocation()
        {
        }
    }


    public class LocationDetail
    {
        [DataMember]
        public int id { get; set; }

        [DataMember]
        public string url { get; set; }

        [DataMember]
        public string urlLink1Mark { get; set; }

        [DataMember]
        public string urlLink1 { get; set; }

        [DataMember]
        public string urlLink2Mark { get; set; }

        [DataMember]
        public string urlLink2 { get; set; }

        [DataMember]
        public string imageUrl { get; set; }

        [DataMember]
        public int rating { get; set; }

        [DataMember]
        public int commentCount { get; set; }

        public LocationDetail(int cid, string cUrl, string cUrlLink1Mark, string cUrlLink1, string cUrlLink2Mark, string cUrlLink2, string cImageUrl, int cRating, int cCommentCnt)
        {
            id = cid;
            url = cUrl;
            urlLink1Mark = cUrlLink1Mark;
            urlLink1 = cUrlLink1;
            urlLink2Mark = cUrlLink2Mark;
            urlLink2 = cUrlLink1;
            imageUrl = cImageUrl;
            rating = cRating;
            commentCount = cCommentCnt;
        }

        public LocationDetail()
        {
        }
    }

}
